package com.hzp.net.client;

import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class NioClient {

    static SelectorProvider provider = SelectorProvider.provider();
    static Selector selector = null;
    private SocketChannel client;
    private ExecutorService executorService = Executors.newCachedThreadPool();

    private boolean connect;

    public NioClient(String host,Integer port) throws IOException {
        selector = provider.openSelector();
        client = provider.openSocketChannel();
        boolean connect = client.connect(new InetSocketAddress(host, port));
        this.connect = connect;
        client.configureBlocking(false);
        client.register(selector, SelectionKey.OP_CONNECT);
    }

    private void init() throws IOException {
        while (!Thread.interrupted()) {
            try {
                selector.select();  //阻塞等待事件
                Iterator<SelectionKey> iterator = this.selector.keys().iterator();  // 事件列表 , key -> channel ，每个KEY对应了一个channel
                while (iterator.hasNext()) {
                    dispatch(iterator.next());  //分发事件
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void dispatch(SelectionKey key) {
        if (key.isConnectable()) {
            this.executorService.submit(new ConnectHandler(key, selector));  //可以写，执行写事件
        } else if (key.isReadable()) {
            this.executorService.submit(new ReadHandler(key, selector));  //可以写，执行写事件
        } else if (key.isWritable()) {
            this.executorService.submit(new WriteHandler(key, selector));  //可以读。执行读事件
        }
    }

    public static void main(String[] args) throws IOException {
        new NioClient("localhost", 888).init();
    }


    private void close() {
        try {
            if (client != null) {
                client.close();
            }
            if (selector != null) {
                selector.close();
            }
            this.connect = false;
            log.info("client closed!");
        } catch (IOException e) {
        }
    }
}
